export const nodes = initialData.nodes.map(node => {
    const name = node.label;
    // 计算文本长度，设置合适的半径
    const textLen = getTextVisualLength(name);
    // 经验公式：每个英文字符约7px，每个中文字符约14px，字体大小约14px，左右留白10px
    const fontSize = 14;
    const padding = 10;
    const radius = Math.max(15, Math.ceil((textLen * fontSize * 0.6 + padding) / 2));
    return {
        id: node.id,
        name: name,
        description: node.description,
        desc_type: node.desc_type || 'plain',
        radius: radius,
        color: node.color || '#4285f4',
        expanded: false,
        x: node.x_position,
        y: node.y_position
    };
});

export const links = initialData.connections.map(conn => ({
    source: conn.source_id,
    target: conn.target_id,
    weight: conn.weight || 1
}));

// 计算每个节点的度数(连接数量)
nodes.forEach(node => {
    node.degree = links.reduce((count, link) => 
        count + (link.source === node.id || link.target === node.id ? 1 : 0), 0);
    // 保持 radius 由文本长度决定，不再根据度数调整
});

export function getTextVisualLength(text) {
    if (!text) return 0;
    let len = 0;
    for (let i = 0; i < text.length; i++) {
        const code = text.charCodeAt(i);
        if ((code >= 0x4e00 && code <= 0x9fff) ||
            (code >= 0x3400 && code <= 0x4dbf) ||
            (code >= 0x20000 && code <= 0x2a6df)) {
            len += 2;
        } else {
            len += 1;
        }
    }
    return len;
}

// 添加边框拖拽功能
export function enableResize(element, onResize) {
    const resizeHandleSize = 8;
    const directions = ['n', 'e', 's', 'w', 'ne', 'nw', 'se', 'sw'];
    
    // 创建拖拽边框
    directions.forEach(dir => {
        const handle = document.createElement('div');
        handle.className = `resize-handle resize-${dir}`;
        handle.style.position = 'absolute';
        handle.style.backgroundColor = 'transparent';
        handle.style.zIndex = '10001';
        
        // 设置位置和大小
        switch(dir) {
            case 'n':
            case 's':
                handle.style.width = '100%';
                handle.style.height = `${resizeHandleSize}px`;
                handle.style.cursor = 'ns-resize';
                break;
            case 'e':
            case 'w':
                handle.style.width = `${resizeHandleSize}px`;
                handle.style.height = '100%';
                handle.style.cursor = 'ew-resize';
                break;
            default: // ne, nw, se, sw
                handle.style.width = `${resizeHandleSize}px`;
                handle.style.height = `${resizeHandleSize}px`;
                handle.style.cursor = `${dir}-resize`;
        }
        
        // 设置位置
        if (dir.includes('n')) handle.style.top = '0';
        if (dir.includes('s')) handle.style.bottom = '0';
        if (dir.includes('e')) handle.style.right = '0';
        if (dir.includes('w')) handle.style.left = '0';
        
        element.appendChild(handle);
        
        // 添加拖拽事件
        handle.addEventListener('mousedown', initDrag);
    });
    
    function initDrag(e) {
        e.preventDefault();
        e.stopPropagation();
        
        const dir = this.className.split(' ')[1].split('-')[1];
        const startX = e.clientX;
        const startY = e.clientY;
        const startWidth = parseInt(document.defaultView.getComputedStyle(element).width, 10);
        const startHeight = parseInt(document.defaultView.getComputedStyle(element).height, 10);
        const startLeft = parseInt(document.defaultView.getComputedStyle(element).left, 10);
        const startTop = parseInt(document.defaultView.getComputedStyle(element).top, 10);
        
        function doDrag(e) {
            const dx = e.clientX - startX;
            const dy = e.clientY - startY;
            
            if (dir.includes('e')) {
                element.style.width = (startWidth + dx) + 'px';
            }
            if (dir.includes('w')) {
                element.style.width = (startWidth - dx) + 'px';
                element.style.left = (startLeft + dx) + 'px';
            }
            if (dir.includes('s')) {
                element.style.height = (startHeight + dy) + 'px';
            }
            if (dir.includes('n')) {
                element.style.height = (startHeight - dy) + 'px';
                element.style.top = (startTop + dy) + 'px';
            }
            
            if (onResize) onResize();
        }
        
        function stopDrag() {
            document.removeEventListener('mousemove', doDrag);
            document.removeEventListener('mouseup', stopDrag);
        }
        
        document.addEventListener('mousemove', doDrag);
        document.addEventListener('mouseup', stopDrag);
    }
}

function getPinyinFirstLetters(text) {
    if (!window.pinyinPro || !text) return '';
    try {
        // 先尝试 type: 'string'，否则 fallback 到 array
        let py = window.pinyinPro.pinyin(text, { pattern: 'first', type: 'string' });
        if (Array.isArray(py)) {
            py = py.map(x => (x || '').toLowerCase()).join('');
        } else if (typeof py === 'string') {
            py = py.toLowerCase().replace(/\s+/g, ''); // 去除所有空格
        } else {
            py = '';
        }
        // 调试输出
        // console.log('[getPinyinFirstLetters]', text, py);
        return py;
    } catch (e) {
        console.warn('[getPinyinFirstLetters error]', text, e);
        return '';
    }
}

export const TAGIFY_CSS_CDN = "/static/visualizer/css/tagify.4.35.3.min.css";
export const TAGIFY_JS_CDN = "/static/visualizer/js/tagify.4.35.3.min.js";

function loadTagifyCDN(callback) {
    // 加载Tagify CSS
    if (!document.querySelector(`link[href="${TAGIFY_CSS_CDN}"]`)) {
        const tagifyCss = document.createElement('link');
        tagifyCss.rel = 'stylesheet';
        tagifyCss.href = TAGIFY_CSS_CDN;
        document.head.appendChild(tagifyCss);
    }
    // 检查Tagify是否为有效构造函数
    function isValidTagify() {
        return typeof window.Tagify === 'function' && 
               window.Tagify.prototype && 
               typeof window.Tagify.prototype.addTags === 'function';
    }
    // 强制移除旧的Tagify脚本
    function removeOldTagifyScript() {
        const oldScript = document.querySelector(`script[src^="${TAGIFY_JS_CDN}"]`);
        if (oldScript) oldScript.remove();
    }
    if (!isValidTagify()) {
        console.warn('[loadTagifyCDN] Tagify not valid, reloading...');
        removeOldTagifyScript();
        // 重新插入Tagify脚本
        const tagifyJs = document.createElement('script');
        tagifyJs.src = TAGIFY_JS_CDN;
        tagifyJs.onload = callback;
        document.head.appendChild(tagifyJs);
    } else if (callback) {
        callback();
        // console.log(`[loadTagifyCDN] Tagify already loaded and valid. Callback ${callback.name} called.`);
    }
}

// --- Tagify同步加载辅助函数 ---
function ensureTagifySyncLoaded() {
    console.log('[ensureTagifySyncLoaded] Ensuring Tagify is synchronously loaded...');

    // 加载Tagify CSS（同步）
    if (!document.querySelector(`link[href="${TAGIFY_CSS_CDN}"]`)) {
        const tagifyCss = document.createElement('link');
        tagifyCss.rel = 'stylesheet';
        tagifyCss.href = TAGIFY_CSS_CDN;
        document.head.appendChild(tagifyCss);
    }
    // 加载Tagify JS（同步阻塞）
    if (!window.Tagify && !document.querySelector(`script[src^="${TAGIFY_JS_CDN}"]`)) {
        const tagifyJs = document.createElement('script');
        tagifyJs.src = TAGIFY_JS_CDN;
        tagifyJs.async = false;
        document.head.appendChild(tagifyJs);
    }

    console.log('[ensureTagifySyncLoaded] Tagify loaded:', window.Tagify);
}

/**
 * 初始化Tagify输入框
 * @param {HTMLElement} inputElement - 输入框DOM元素
 * @param {Array} nodes - 节点列表
 * @param {Object} options - 配置选项
 * @param {Function} [onPick] - 拾取节点回调函数
 * @returns {Tagify} Tagify实例
 */
function initTagify(inputElement, nodes, options = {}, onPick) {
    if (!window.Tagify) return null;
    
    // 默认配置
    const defaultOptions = {
        tagTextProp: 'name',
        valueProp: 'id',
        enforceWhitelist: true,
        skipInvalid: true,
        autoComplete: false,
        editTags: false,
        maxTags: 1,
        dropdown: { enabled: 0 },
        originalInputValueFormat: valuesArr => valuesArr.map(item => item.id).join(',')
    };

    // 准备白名单数据
    const whitelist = nodes
        .filter(n => n.id != null && n.id !== '')
        .map(n => ({
            id: String(n.id),
            name: n.name ? String(n.name) : String(n.id),
            value: String(n.id)
        }));

    // 合并配置
    const tagifyOptions = { ...defaultOptions, ...options, whitelist };

    // 创建Tagify实例
    const tagify = new Tagify(inputElement, tagifyOptions);

    // 添加样式
    const style = document.createElement('style');
    style.innerHTML = `
        .tagify__dropdown, .tagify__dropdown__wrapper { display: none !important; }
        .tagify {
            min-height: 36px !important;
            max-height: 120px !important;
            width: 100% !important;
            box-sizing: border-box !important;
            overflow-y: auto !important;
        }
        .tagify__input, .tagify__input:focus {
            min-height: 28px !important;
            height: 28px !important;
            max-height: 60px !important;
            padding: 4px 8px !important;
        }
        .tagify__tag {
            margin: 2px 4px 2px 0 !important;
        }
    `;
    document.head.appendChild(style);

    // 验证标签
    tagify.on('beforeTagAdd', function(e) {
        const id = e.detail?.data?.id;
        const valid = id && tagify.settings.whitelist.some(n => n.id === id);
        if (!valid) {
            e.preventDefault();
            return false;
        }
    });

    // 阻止默认按键行为
    tagify.DOM.input.addEventListener('keydown', function(e) {
        if (["Enter", ",", "Tab"].includes(e.key)) {
            e.preventDefault();
        }
    });

    // 拾取节点功能
    if (onPick) {
        tagify.DOM.input.addEventListener('drop', function(e) {
            if (e.dataTransfer?.getData('text/plain')?.startsWith('__pick_node__')) {
                const nodeId = e.dataTransfer.getData('nodeId');
                const node = nodes.find(n => n.id == nodeId);
                if (node) onPick(node);
            }
        });
    }

    return tagify;
}

// 更新Tagify实例的whitelist
function updateTagifyWhitelist(tagifyInstance, newWhitelist) {
    if (tagifyInstance && Array.isArray(newWhitelist)) {
        tagifyInstance.settings.whitelist = newWhitelist;
        // tagifyInstance.dropdown.hide();
        // tagifyInstance.dropdown.show(); // 立即刷新下拉
    }
}

// 假设 removeNodeSearch, addNodeSearch 等都是 d3.select(input) 对象
function registerTagifyInstance(input) {
    if (!window.tagifyInstances) window.tagifyInstances = [];
    // 移除已存在的同input实例
    window.tagifyInstances = window.tagifyInstances.filter(inst => inst.input !== input.node());
    if (input.node()._tagifyInstance) {
        window.tagifyInstances.push({ input: input.node(), instance: input.node()._tagifyInstance });
    }
}

/**
 * 通用搜索匹配函数
 * @param {string} searchTerm - 搜索关键词
 * @param {Array} whitelist - 节点白名单
 * @param {Array} selectedIds - 已选节点ID列表
 * @param {Function} onMatchClick - 匹配项点击回调
 * @param {Object} container - D3选择的容器元素
 * @param {Function} getPinyin - 拼音转换函数
 */
function doMatchGeneric(searchTerm, whitelist, selectedIds, onMatchClick, container, getPinyin) {
    container.selectAll('div').remove();
    if (searchTerm) {
        const matches = whitelist.filter(node => {
            if (!node.name) return false;
            if (selectedIds.includes(node.id)) return false;
            const nameLower = node.name.toLowerCase();
            if (nameLower.includes(searchTerm)) return true;
            const pyFirst = getPinyin(node.name);
            if (pyFirst && searchTerm && pyFirst.includes(searchTerm)) return true;
            if (String(node.id).toLowerCase().includes(searchTerm)) return true;
            return false;
        });

        if (matches.length) {
            matches.forEach(node => {
                container.append('div')
                    .html(`<strong>${node.name || 'Unnamed'}</strong> (ID: ${String(node.id).substring(0, 8)}...)`)
                    .style('padding', '5px')
                    .style('cursor', 'pointer')
                    .style('border-bottom', '1px solid #eee')
                    .on('mousedown', function() {
                        onMatchClick(node);
                    });
            });
            container.style('display', 'block');
        } else {
            container.style('display', 'none');
        }
    } else {
        container.style('display', 'none');
    }
}

/**
 * 绘制节点与弹窗之间的连线
 * @param {HTMLElement} popupDiv 弹窗元素
 * @param {Object} nodeData 节点数据
 */
function drawPopupNodeCurve(popupDiv, nodeData) {
    const svgNode = document.querySelector('svg');
    const t = d3.zoomTransform(svgNode);
    const svgRect = svgNode.getBoundingClientRect();
    
    // 节点屏幕坐标
    const nodeScreenX = svgRect.left + t.applyX(nodeData.x);
    const nodeScreenY = svgRect.top + t.applyY(nodeData.y);
    
    // 弹窗锚点（左上角） - 弹窗位置不受缩放影响，直接使用屏幕坐标
    const popupRect = popupDiv.getBoundingClientRect();
    const popupAnchorX = popupRect.left;
    const popupAnchorY = popupRect.top;
    
    // 转换为SVG坐标
    const svgX1 = t.applyX(nodeData.x);
    const svgY1 = t.applyY(nodeData.y);
    // 弹窗端坐标不需要除以缩放因子k，因为弹窗位置是固定的屏幕坐标
    const svgX2 = popupAnchorX - svgRect.left;
    const svgY2 = popupAnchorY - svgRect.top;
    
    // 曲线控制点
    const cX = (svgX1 + svgX2) / 2;
    const cY = (svgY1 + svgY2) / 2 - 40;
    
    // 绘制path
    const existingCurve = d3.select(`.node-details-curve[data-node-id="${nodeData.id}"]`);
    if (existingCurve.empty()) {
        d3.select('svg').append('path')
            .attr('class', 'node-details-curve')
            .attr('data-node-id', nodeData.id)
            .attr('d', `M${svgX1},${svgY1} Q${cX},${cY} ${svgX2},${svgY2}`)
            .attr('fill', 'none')
            .attr('stroke', '#4285f4')
            .attr('stroke-width', 2)
            .attr('opacity', 0.7);
    } else {
        existingCurve
            .attr('d', `M${svgX1},${svgY1} Q${cX},${cY} ${svgX2},${svgY2}`);
    }
}

// 节点弹窗注册表 - 存储节点ID到弹窗信息的映射
export const nodePopupRegistry = new Map();

/**
 * 重绘所有弹窗与节点之间的连线
 */
function redrawLineOfPopupAndNode() {
    if (nodePopupRegistry?.size) {
        nodePopupRegistry.forEach((popupInfo, nodeId) => {
            const node = popupInfo.nodeData;
            if (node && popupInfo.popupElement) {
                drawPopupNodeCurve(popupInfo.popupElement, node);
            }
        });
    }
}

export {
    getPinyinFirstLetters,
    loadTagifyCDN,
    initTagify,
    doMatchGeneric,
    ensureTagifySyncLoaded,
    updateTagifyWhitelist,
    registerTagifyInstance,
    drawPopupNodeCurve,
    redrawLineOfPopupAndNode
};